package com.duwei.util;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.duwei.pojo.User;
import com.duwei.service.UserService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Log4j2
public class User1ExcelListener extends AnalysisEventListener<User>{
    private UserService userService;
    private ExcelWriter excelWriter;
    private WriteSheet writeSheet;
    private RedisTemplate<String,String> redisTemplate;

    public ResponseResult responseResult;

    public User1ExcelListener(UserService userService){
        this.userService = userService;
    }
    public User1ExcelListener(UserService userService, ExcelWriter excelWriter,WriteSheet writeSheet,RedisTemplate<String,String> redisTemplate){

        this.userService = userService;
        this.excelWriter = excelWriter;
        this.writeSheet = writeSheet;
        this.redisTemplate = redisTemplate;
        responseResult = new ResponseResult();
    }

    public User1ExcelListener(){

    }

    //固定每次收集100条，然后清理list，方便内存释放
    private static final int BATCH_COUNT = 5000;
    private static final int ERROR_COUNT = 5000;

    private List<User> errorList = new ArrayList<>(ERROR_COUNT);


    //缓存数据  类会扩容，所以可以直接设置大小
    private List<User> cacheList = new ArrayList<>(BATCH_COUNT);








    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        if (exception instanceof ExcelDataConvertException) {
            log.error("======>>>解析异常：", exception);
            System.err.println("Data conversion error at row " + context.readRowHolder().getRowIndex());
            throw exception;
        }
    }

    @Override
    public void invoke(User user, AnalysisContext analysisContext) {
        //判断是否存在这条数据
        Integer count = user.getCount();
        BloomHash<Integer> integerBloomHash = new BloomHash<>();
        long bloomHash = integerBloomHash.getBloomHash(count);
        Boolean bloomhash = redisTemplate.opsForValue().getBit("bloomhash", bloomHash);
        if(bloomhash){
            //存在，不一定真的存在，可能不存在
            User count1 = userService.getOne(new QueryWrapper<User>().eq("count", user.getCount()));
            if(count1 != null){
                errorList.add(user);
                if(errorList.size()>=ERROR_COUNT){
                    excelWriter.write(errorList,writeSheet);
                    errorList.clear();
                }
                return;
            }
        }
        cacheList.add(user);
        if(cacheList.size()>=BATCH_COUNT){
            userService.saveBatch(cacheList);
            BloomHash<Integer> integerBloomHash1 = new BloomHash<>();
            for(User user1 : cacheList){
                redisTemplate.opsForValue().setBit("bloomhash",integerBloomHash1.getBloomHash(user1.getCount()),true);
            }
            cacheList.clear();
        }

    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        userService.saveBatch(cacheList);
        BloomHash<Integer> integerBloomHash1 = new BloomHash<>();
        for(User user1 : cacheList){
            redisTemplate.opsForValue().setBit("bloomhash",integerBloomHash1.getBloomHash(user1.getCount()),true);
        }
        cacheList.clear();
        excelWriter.write(errorList,writeSheet);
        errorList.clear();
        log.info("所有数据处理完毕");
    }

    /**
     * 解析表头数据
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        log.info("表头数据:{}", ConverterUtils.convertToStringMap(headMap,context));
    }

}
